package com.zxy.study.ui.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Build;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.View;

import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.viewpager2.widget.ViewPager2;

import com.zxy.study.R;
import com.zxy.study.utils.DimensUtil;


/**
 * @author : Shonn.Zhang
 * @email  : shonn.zhang@mart.blue
 * @time   : 2020/9/22 14:13
 * @desc   : 圆点或方形指示器
 * 1、用于图片滑动指示或者轮播图指示
 * 2、用于密码输入进度指示
 */
public class BlueIndicatorView extends View {

    /**
     * 指示点的形状
     * 1：圆形
     * 2：方形
     */
    private static final int SHAPE_CIRCLE = 1;
    private static final int SHAPE_SQUARE = 2;

    /**
     * 绘制模式
     * 1：滑动模式，高亮显示选中点
     * 2：密码模式，高亮显示输入进度
     */
    private static final int MODE_SLIDE = 1;
    private static final int MODE_PWD = 2;

    //指示点大小
    private int mIndicatorRadius;
    private int mNormalColor;
    private int mSelectedColor;
    //指示点间隔
    private int mPadding;
    //间隔是否等分
    private boolean isPaddingEqual;

    //指示点数量
    private int mIndicatorNum;

    //指示点形状
    private int mIndicatorShape;
    //当前选中的指示点
    private int mSelectedIndex;

    //绘制模式
    private int mIndicatorMode;
    //当前输入进度
    private int mIndicatorProgress;

    private Paint mPaint;


    //开始绘制的数量限制，及超过几个菜开始绘制
    private int mDrawLimit = 1;

    private int mXOffset;
    private int mYOffset;

    public BlueIndicatorView(Context context) {
        this(context, null);
    }

    public BlueIndicatorView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public BlueIndicatorView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context.obtainStyledAttributes(attrs, R.styleable.BlueIndicatorView, defStyleAttr, 0));
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public BlueIndicatorView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context.obtainStyledAttributes(attrs, R.styleable.BlueIndicatorView, defStyleAttr, defStyleRes));
    }

    private void init(TypedArray ta) {
        mIndicatorRadius = ta.getDimensionPixelSize(R.styleable.BlueIndicatorView_indicator_radius, 7);
        mNormalColor = ta.getColor(R.styleable.BlueIndicatorView_indicator_color_normal, Color.parseColor("#7FFFFFFF"));
        mSelectedColor = ta.getColor(R.styleable.BlueIndicatorView_indicator_color_selected, Color.WHITE);
        mPadding = ta.getDimensionPixelOffset(R.styleable.BlueIndicatorView_indicator_padding, DimensUtil.dp2px(getContext(), 10));
        isPaddingEqual = ta.getBoolean(R.styleable.BlueIndicatorView_indicator_padding_equal, false);
        mIndicatorNum = ta.getInteger(R.styleable.BlueIndicatorView_indicator_num, 0);

        TypedValue shapeValue = new TypedValue();
        if (ta.getValue(R.styleable.BlueIndicatorView_indicator_shape, shapeValue)) {
            mIndicatorShape = shapeValue.data;
        } else {
            mIndicatorShape = SHAPE_CIRCLE;
        }

        TypedValue modeValue = new TypedValue();
        if (ta.getValue(R.styleable.BlueIndicatorView_indicator_mode, modeValue)) {
            mIndicatorMode = modeValue.data;
        } else {
            mIndicatorMode = MODE_SLIDE;
        }

        ta.recycle();

        mPaint = new Paint();
        mPaint.setAntiAlias(true);

    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (mIndicatorMode == MODE_SLIDE && mIndicatorNum <= mDrawLimit) {
            setMeasuredDimension(MeasureSpec.makeMeasureSpec(0, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(0, MeasureSpec.EXACTLY));
            return;
        }

        int measureWidth = 2 * mIndicatorRadius * mIndicatorNum + mPadding * (mIndicatorNum - 1) + getPaddingStart() + getPaddingEnd();
        int measureHeight = mIndicatorRadius * 2 + getPaddingTop() + getPaddingBottom();
        mXOffset = getPaddingStart();
        mYOffset = getPaddingTop();

        if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY) {
            int width = MeasureSpec.getSize(widthMeasureSpec);
            int resultWidth = Math.max(measureWidth, width);

            if (isPaddingEqual && mIndicatorNum > 1) {
                mPadding = Math.max((width - 2 * mIndicatorRadius * mIndicatorNum - getPaddingStart() - getPaddingEnd()) / (mIndicatorNum - 1), 0);
            } else {
                mXOffset = Math.max((resultWidth - measureWidth) / 2, 0);
            }

            measureWidth = resultWidth;
        }

        if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.EXACTLY) {
            int resultHeight = Math.max(measureHeight, MeasureSpec.getSize(heightMeasureSpec));
            mYOffset = Math.max((resultHeight - mIndicatorRadius * 2) / 2, 0);
            measureHeight = resultHeight;
        }

        setMeasuredDimension(MeasureSpec.makeMeasureSpec(measureWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(measureHeight, MeasureSpec.EXACTLY));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (mIndicatorMode == MODE_SLIDE && mIndicatorNum <= mDrawLimit) return;

        //绘制未选中的点
        mPaint.setColor(mNormalColor);
        for (int i = 0; i < mIndicatorNum; i++) {
            mPaint.setColor(getIndicatorColor(i));
            if (mIndicatorShape == SHAPE_SQUARE) {
                drawSquare(canvas, i);
            } else {
                drawCircle(canvas, i);
            }
        }
    }

    /**
     * 获取绘制指示点的颜色
     *
     * @param index 指示点的位置
     * @return
     */
    private int getIndicatorColor(int index) {
        if (mIndicatorMode == MODE_SLIDE) {
            return index == mSelectedIndex ? mSelectedColor : mNormalColor;
        }
        return index < mIndicatorProgress ? mSelectedColor : mNormalColor;
    }

    /**
     * 绘制正方形
     *
     * @param canvas
     * @param index
     */
    private void drawSquare(Canvas canvas, int index) {
        int left = mXOffset + index * 2 * mIndicatorRadius + index * mPadding;

        canvas.drawRect(left, mYOffset, left + 2 * mIndicatorRadius, mYOffset + 2 * mIndicatorRadius, mPaint);
    }

    /**
     * 绘制圆点
     *
     * @param canvas
     * @param index
     */
    private void drawCircle(Canvas canvas, int index) {
        int cx = mXOffset + (2 * index + 1) * mIndicatorRadius + index * mPadding;
        int cy = mYOffset + mIndicatorRadius;
        canvas.drawCircle(cx, cy, mIndicatorRadius, mPaint);
    }

    /**
     * 设置绘制圆点数量
     *
     * @param indicatorNum
     */
    public void setIndicatorNum(int indicatorNum) {
        setVisibility(indicatorNum > mDrawLimit ? VISIBLE : GONE);
        if (mIndicatorNum != indicatorNum) {
            this.mIndicatorNum = indicatorNum;
            requestLayout();
        }
    }

    /**
     * 设置选中点的位置
     * {@linkplain #mIndicatorMode} 等于 {@linkplain #MODE_SLIDE} 有效
     *
     * @param index
     */
    public void setSelectIndex(int index) {
        if (mIndicatorMode == MODE_SLIDE && index >= 0 && index < mIndicatorNum) {
            this.mSelectedIndex = index;
            postInvalidate();
        }
    }

    /**
     * 设置指示点的输入进度
     * {@linkplain #mIndicatorMode} 等于 {@linkplain #MODE_PWD} 有效
     *
     * @param progress
     */
    public void setIndicatorProgress(int progress) {
        if (mIndicatorMode == MODE_PWD && progress >= 0 && progress <= mIndicatorNum) {
            this.mIndicatorProgress = progress;
            postInvalidate();
        }
    }

    /**
     * 绑定ViewPager2
     *
     * @param viewPager2
     */
    public void setUpViewPager2(ViewPager2 viewPager2) {
        if (viewPager2 == null) return;
        viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
            @Override
            public void onPageSelected(int position) {
                setSelectIndex(position);
            }
        });
    }
}
